﻿/*************************************************
* 文 件 名：DataListener
* 命名空间：WSNs
* 功    能：
* 作    者：ZGW (zgw@cqu.edu.cn)
* 团    队：Wireless Sensor Networks (WSNs)
* 创建时间：2015/1/19 10:46:51
* 版 本 号：V1.0.0.0
* 修改日志：
*************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WSNs
{
    internal class DataListener
    {
        //收到数据事件
        //public Action<List<byte>> ReceivedDataEvent;
        //public CtlNodeInfo ctlNodeInfo = new CtlNodeInfo();
        public Action<int, int[,],int> LinkDectReceivedEvent;
        public Action<CtlNode> AddrReceivedEvent;
        public Action<AcqStructure> DataBackAcq;
        public Action<List<byte>,DataStutas> TestEvent;
        public delegate void ReceivedDataEventHandler(int nodeID, List<byte> data);
        public ReceivedDataEventHandler ReceivedDataEvent;
        private NodesData _nodesData = NodesData.GetInstance();

        private BackgroundWorker _BgAnalyze = new BackgroundWorker();
        private SerialPort _serialPort = new SerialPort();
        private List<byte> datalist = new List<byte>();
        private StructBytes _structBytes = new StructBytes(); //结构体与数据转换

        public int[,] Signal = new int[10, 2];
       
        //串口参数
        private string _spPortName;
        private int _spBaudRate = -1;
        private int _spDataBits = 8;
        private System.IO.Ports.Parity _spParity = System.IO.Ports.Parity.None;
        private System.IO.Ports.StopBits _spStopBits = System.IO.Ports.StopBits.One;

        private AcqStructure _defaultAcq = new AcqStructure
        {
            AcqMode = WSNs.AcqMode.Freedom,
            FileID = 1,
            CoupleMode = WSNs.CoupleMode.AC,
            StorageLocation = WSNs.StorageLocation.MicroSD,
            Frequency = 51200
        };

        public void Init()
        {
            _serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort_DataReceived);

            //初始化后台处理线程
            _BgAnalyze.DoWork += new DoWorkEventHandler(BgAnalyze_DoWork);
            _BgAnalyze.RunWorkerAsync();

        }

        #region 串口操作

        public bool SendCMD(byte[] bytes)
        {
            if (!_serialPort.IsOpen)
            {
                System.Windows.Forms.MessageBox.Show("串口有错误！");
                return false;
            }
            
            serialPort_SendData(bytes, 0, bytes.Count());
            return true;
        }

        //设置串口
        public void SetSerialPort(string portName, int baudRate)
        {
            _spPortName = portName;
            _spBaudRate = baudRate;
        }

        //打开串口
        public bool OpenSerialPort()
        {
            if (string.IsNullOrEmpty(_spPortName) || _spBaudRate <= 0)
            {
                System.Windows.Forms.MessageBox.Show("串口参数错误！");
                return false;
            }

            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Close();
                }
                _serialPort.PortName = _spPortName;
                _serialPort.BaudRate = _spBaudRate;
                _serialPort.Parity = _spParity;
                _serialPort.DataBits = _spDataBits;
                _serialPort.StopBits = _spStopBits;
                _serialPort.Open();
                return true;
            }
            catch (Exception ex)
            {
                string tmp = ex.ToString();
                System.Windows.Forms.MessageBox.Show("指定串口无法打开，有可能被其他程序占用！");
                return false;
            }
        }
        
        public void CloseSerialPort()
        {
            try
            {
                _serialPort.Close();
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString());
            }
        }

        //清除所有收到的数据
        public void ClearAlldata()
        {
            datalist.Clear();
        }

        public bool SerialPortIsOpen()
        {
            return _serialPort.IsOpen;
        }

        private void serialPort_SendData(byte[] bytes, int offset, int count)
        {
            _serialPort.Write(bytes, offset, count);
        }

        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int bytesToRead = _serialPort.BytesToRead;
            int bytesRead = 0;
            byte[] bytes = new byte[bytesToRead];

            bytesRead = _serialPort.Read(bytes, 0, bytesToRead);
            if (bytesRead == 0)
            {
                return;
            }
            else
            {
                BackgroundWorker _bgWorker = new BackgroundWorker(); //读取数据后台
                _bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
                _bgWorker.RunWorkerAsync(bytes);
            }
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            byte[] bytes = (byte[]) e.Argument;
            lock (this)
            {
                datalist.AddRange(bytes);
            }
        }

        #endregion

        //后台处理线程
        private void BgAnalyze_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if (datalist.Count < 4)
                {
                    System.Threading.Thread.Sleep(5);
                }
                else if (datalist[0] == 0xAA && datalist[1] == 0x55)
                {
                    var lengthTemp = datalist[2] + (datalist[3] << 8) + 6;
                    if (datalist.Count < lengthTemp) continue; //判断是否接收完数据
                    if (datalist[lengthTemp - 2] != 0x55 || datalist[lengthTemp - 1] != 0xAA) //判断数据尾是否正确
                    {
                        List<byte> temp = datalist.ToList();
                        datalist.Clear();
                        TestEvent(temp, DataStutas.EndErr);
                        continue;
                    }
                    //判断数据包类型
                    switch ((SerialPackType) datalist[4])
                    {
                        case SerialPackType.DataPack:
                            byte id = datalist[5];
                            var serial = datalist[6] + (datalist[7] << 8);
                            if (serial == 0) //第0个包为文件参数
                            {
                                var acq = _structBytes.ByteToStruct(datalist.GetRange(8, 16).ToArray(), 
                                    typeof (AcqStructure));
                                DataBackAcq((AcqStructure) acq);
                                _nodesData.SaveAllData(id, datalist.GetRange(0, lengthTemp));//存取所有数据包
                                lock (this)
                                    datalist.RemoveRange(0, lengthTemp);
                                break;
                            }
                            if (_nodesData.GetLastSerial(id, lengthTemp) == serial) //序列号相同，丢掉
                            {
                                lock (this)
                                    datalist.RemoveRange(0, lengthTemp);
                                break;
                                //TestEvent(serial,0);
                            }
                            var stemp = _nodesData.GetLastSerial(id, lengthTemp);
                            if (serial - stemp > 1) //包序号不连续
                                TestEvent(new List<byte>(), DataStutas.PackSerialResErr);

                            _nodesData.SaveAllData(id, datalist.GetRange(0, lengthTemp));//存取所有数据包
                            ReceivedDataEvent(id, datalist.GetRange(8, lengthTemp - 10));
                            lock (this)
                                datalist.RemoveRange(0, lengthTemp);
                            break;
                        case SerialPackType.CmdPack:
                            break;
                        case SerialPackType.AnswerPack:
                            break;
                        case SerialPackType.AddrPack:
                            CtlNode node = new CtlNode();
                            node.NodeType = (NodesType) datalist[5];
                            node.FatherNode = datalist[6];
                            node.NodeID = datalist[7];
                            _defaultAcq.NodeID = (byte)node.NodeID;
                            node.AcqStructure = _defaultAcq;
                            AddrReceivedEvent(node);
                            lock (this)
                            {
                                datalist.RemoveRange(0, lengthTemp);
                            }
                            TestEvent(new List<byte>(), DataStutas.AddrPackRev);
                            break;
                        case SerialPackType.LinkDectPack:
                            int Node = 0;
                            byte nodeNum = datalist[5];
                            byte Lqi = datalist[7];
                            byte Rssi = datalist[8];
                            if (nodeNum == 0)
                            {
                                Signal[0, 0] = 0;
                            }
                            for (int k = 0; k < nodeNum; k++)
                            {
                                Signal[k, 0] = datalist[6 + 3 * k];
                                Node = datalist[6 + 3 * k];
                                Signal[k, 1] = datalist[7 + k * 3];
                               /* if (datalist[7 + k * 3] == 0)
                                { 
                                    Signal[k, 1] = 0;                                
                                }
                                if (datalist[7 + k * 3] > 0 && datalist[7 + k * 3] <= 16)
                                    Signal[k, 1] = 1;
                                if (datalist[7 + k * 3] > 16 && datalist[7 + k * 3] <= 32)
                                    Signal[k, 1] = 2;
                                if (datalist[7 + k * 3] > 32 && datalist[7 + k * 3] <= 64)
                                    Signal[k, 1] = 3;
                                if (datalist[7 + k * 3] > 64 && datalist[7 + k * 3] <= 128)
                                    Signal[k, 1] = 4;
                                if (datalist[7 + k * 3] > 128 && datalist[7 + k * 3] <= 192)
                                    Signal[k, 1] = 5;
                                if (datalist[7 + k * 3] > 192 && datalist[7 + k * 3] < 255)
                                    Signal[k, 1] = 6;*/
                                LinkDectReceivedEvent(Node, Signal, nodeNum);
                                _nodesData._nodeIsLive[Node] = true;  //节点在线检测
                            }

                            lock (this)
                            {
                                datalist.RemoveRange(0, lengthTemp);
                            }
                            TestEvent(new List<byte>(), DataStutas.LinkDectPackRec);
                            break;
                       /* case SerialPackType.NodeState:
                            TestEvent(new List<byte>(), DataStutas.NodeState);
                            break;*/
                        default:
                            List<byte> temp = datalist.ToList();
                            datalist.Clear();
                            //TestEvent(temp, DataStutas.SerialTypeErr);
                            break;
                    }
                }
                else
                {
                    List<byte> temp = datalist.ToList();
                    datalist.Clear();
                    //TestEvent(temp, DataStutas.StartErr);
                    
                }
            }
        }

        
    }
}
